package me.flyray.bsin.server.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import lombok.extern.slf4j.Slf4j;
import me.flyray.bsin.constants.ResponseCode;
import me.flyray.bsin.context.BsinServiceContext;
import me.flyray.bsin.context.LoginInfoContextHelper;
import me.flyray.bsin.domain.LoginUser;
import me.flyray.bsin.exception.BusinessException;
import me.flyray.bsin.facade.service.UserService;
import me.flyray.bsin.server.config.TenantConfig;
import me.flyray.bsin.server.domain.*;
import me.flyray.bsin.server.enums.TenantOrgAppType;
import me.flyray.bsin.server.enums.UserType;
import me.flyray.bsin.server.mapper.*;
import me.flyray.bsin.utils.BsinPageUtil;
import me.flyray.bsin.utils.BsinSnowflake;
import me.flyray.bsin.utils.EmptyChecker;
import me.flyray.bsin.utils.Pagination;
import me.flyray.bsin.utils.RespBodyHandler;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Slf4j
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl implements UserService{

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserPostMapper userPostMapper;
    @Autowired
    private OrgMapper orgMapper;
    @Autowired
    private PostMapper postMapper;
    @Autowired
    private OrgPostMapper orgPostMapper;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private AppMapper appMapper;
    @Autowired
    private OrgAppMapper orgAppMapper;
    @Autowired
    private TenantMapper tenantMapper;
    @Autowired
    private TenantAppMapper tenantAppMapper;
    @Autowired
    private AppFunctionMapper appFunctionMapper;
    @Autowired
    private MenuMapper menuMapper;
    @Autowired
    private RoleMenuMapper roleMenuMapper;
    @Autowired
    private PostRoleMapper postRoleMapper;
    @Autowired
    private ProductMapper productMapper;

    /**
     * 新增
     * @param requestMap
     * @return
     */
    @Override
    public Map<String, Object> add(Map<String, Object> requestMap) {
        SysUser sysUser = BsinServiceContext.getReqBodyDto(SysUser.class, requestMap);
        LoginUser loginUser = LoginInfoContextHelper.getLoginUser();
        String tenantId = loginUser.getTenantId();
        String userId = BsinSnowflake.getId();
        sysUser.setTenantId(tenantId);
        sysUser.setUserId(userId);
        userMapper.insertUser(sysUser);
        return RespBodyHandler.setRespBodyDto(sysUser);
    }

    /**
     * 新增商户用户
     * 1、为租户添加商户机构（商户为租户下的一个商户部门）
     * 2、为部门添加新的岗位
     * 3、添加商户用户
     * 4、给用户分配新岗位
     * 5、新建角色，给角色添加基础功能菜单
     * 6、给岗位添加角色
     * @param requestMap
     * @return
     */
    @Transactional
    @Override
    public Map<String, Object> addMerchantUser(Map<String, Object> requestMap) {
        log.info("请求 addMerchantUser 参数: {}",requestMap);
        SysUser sysUser = BsinServiceContext.getReqBodyDto(SysUser.class, requestMap);

        String merchantNo = (String) requestMap.get("merchantNo");
        String merchantName = (String) requestMap.get("merchantName");
        String tenantId = (String) requestMap.get("tenantId");
        // 查询租户顶级机构，在租户顶级机构下添加一个部门
        SysOrg sysOrg = orgMapper.selectTopOrgByTenantId(sysUser.getTenantId());

        // 在租户下添加商户部门
        SysOrg merchantOrg = new SysOrg();
        String orgId = BsinSnowflake.getId();
        merchantOrg.setTenantId(sysUser.getTenantId());
        merchantOrg.setOrgId(orgId);
        merchantOrg.setParentId(sysOrg.getOrgId());
        merchantOrg.setOrgName(merchantName);
        merchantOrg.setOrgCode(merchantName);
        orgMapper.insertOrg(merchantOrg);

        // 添加添加商户部门用户
        sysUser.setType(UserType.MERCHANT.getCode());
        sysUser.setOrgId(orgId);
        sysUser.setUserId(merchantNo);
        userMapper.insertUser(sysUser);

        // 添加商户岗位 建立机构与岗位的关系、用户与岗位的关系
        String postId = BsinSnowflake.getId();
        SysPost sysPost = new SysPost();
        sysPost.setPostId(postId);
        sysPost.setTenantId(sysUser.getTenantId());
        sysPost.setPostCode(merchantNo);
        sysPost.setPostName(sysUser.getUsername() + "岗");
        postMapper.insertPost(sysPost);
        List<String> postIds = new ArrayList<>();
        postIds.add(postId);
        orgPostMapper.assignPosts(orgId, postIds);

        // 给用户分配新岗位
        userPostMapper.assignPosts(merchantNo, postIds);

        // TODO 一个租户代理两个产品会存在两个基础应用
        // 查询商户对应租户代理的产品的基础应用 一个租户对应一个产品
        SysTenant sysTenant = tenantMapper.selectTenantInfoByTenantId(tenantId);
        SysProduct sysProduct = productMapper.selectByProductCode(sysTenant.getProductCode());
        SysApp baseApp = tenantAppMapper.selectTenantBaseApp(sysUser.getTenantId(), sysProduct.getProductId());
        // 给商户部门分配可以访问的应用
        orgAppMapper.authorizeApp(orgId, baseApp.getAppId(), TenantOrgAppType.AUTH.getCode());

        // 查出基础应用的基础功能
        List<SysAppFunction> appBaseFunctionList = appFunctionMapper.selectBaseFunctionListByAppId(baseApp.getAppId());
        // 查询基础功能对应的菜单
        List<String> appBaseFunctionIds = new ArrayList<>();
        for (SysAppFunction sysAppFunction : appBaseFunctionList) {
            appBaseFunctionIds.add(sysAppFunction.getAppFunctionId());
        }
        // 查询基础功能菜单
        List<String> authMenuIds = menuMapper.selectListByAppFunctionIds(appBaseFunctionIds);

        // 新增角色
        String roleId = BsinSnowflake.getId();
        SysRole sysRole = new SysRole(roleId, "商户默认角色", "0", baseApp.getAppId(), sysUser.getTenantId(), 4);
        roleMapper.insert(sysRole);

        // 为该角色添加基础功能菜单
        roleMenuMapper.authorizeMenus(baseApp.getAppId(), roleId, authMenuIds);

        List<String> roleIds = new ArrayList<>();
        roleIds.add(roleId);
        // 建立商户岗位与角色的关系
        postRoleMapper.assignRoles(postId, roleIds, baseApp.getAppId());

        return RespBodyHandler.setRespBodyDto(sysUser);
    }

    /**
     * 只支持订阅具体应用下的功能
     * 1、找到相关功能对应的菜单
     * 2、新建角色
     * 3、删除功能对应菜单
     * 4、给角色添加功能菜单菜单
     * 5、将角色分配给岗位
     * @param requestMap
     * @return
     */
    @Override
    public Map<String, Object> authMerchantFunction(Map<String, Object> requestMap) {
        List<String> appFunctionIds = (List<String>) requestMap.get("appFunctionIds");
        String tenantId = (String) requestMap.get("tenantId");
        String merchantNo = (String) requestMap.get("merchantNo");
        String appId = (String) requestMap.get("appId");

        // 查询订阅功能对应的菜单
        List<String> authMenuIds = menuMapper.selectListByAppFunctionIds(appFunctionIds);
        // 新增角色
        String roleId = BsinSnowflake.getId();
        SysRole sysRole = new SysRole(roleId, "商户默认角色", "0", appId, tenantId, 4);
        roleMapper.insert(sysRole);
        // 为该角色添加基础功能菜单
        roleMenuMapper.authorizeMenus(appId, roleId, authMenuIds);

        // 添加商户默认岗位的code是商户号
        SysPost sysPost = postMapper.getPostByPostCode(merchantNo);
        List<String> roleIds = new ArrayList<>();
        roleIds.add(roleId);
        // 建立商户岗位与角色的关系
        postRoleMapper.assignRoles(sysPost.getPostId(), roleIds, appId);

        return RespBodyHandler.RespBodyDto();
    }


    /**
     * 删除
     * @param requestMap
     * @return
     */
    @Override
    public Map<String, Object> delete(Map<String, Object> requestMap) {
        String userId = (String) requestMap.get("userId");
        // 检查用户是否存在分配了岗位，如果存在抛出异常提示用户
        SysUser postByUserId = userPostMapper.getPostByUserId(userId);
        if (EmptyChecker.isEmpty(userId)) {
            throw new BusinessException(ResponseCode.ID_NOT_ISNULL);
        }
        else if (EmptyChecker.notEmpty(postByUserId)) {
            throw new BusinessException(ResponseCode.POSITION_USER_IS_RELATED);
        }
        userMapper.deleteById(userId);
        return RespBodyHandler.RespBodyDto();
    }

    /**
     * 更新
     * @param requestMap
     * @return
     */
    @Override
    public Map<String, Object> edit(Map<String, Object> requestMap) {
        SysUser sysUser = BsinServiceContext.getReqBodyDto(SysUser.class, requestMap);
        String userId = (String) requestMap.get("userId");
        if (EmptyChecker.isEmpty(userId)) {
            throw new BusinessException(String.valueOf(ResponseCode.ID_NOT_ISNULL));
        }
        sysUser.setUserId(userId);
        userMapper.updateById(sysUser);
        return RespBodyHandler.setRespBodyDto(sysUser);
    }

    /**
     * 根据用户名查询用户
     * @param requestMap
     * @return
     */
    @Override
    public Map<String, Object> getUserList(Map<String, Object> requestMap) {
        LoginUser loginUser = LoginInfoContextHelper.getLoginUser();
        String tenantId = loginUser.getTenantId();
        String phone = (String) requestMap.get("phone");
        String orgId = (String) requestMap.get("orgId");
        String nickname = (String) requestMap.get("nickname");
        String username = (String) requestMap.get("username");
        List<SysUser> sysUser = userMapper.selectList(tenantId,nickname,username,phone,orgId);
        return RespBodyHandler.setRespBodyListDto(sysUser);
    }
    /**
     * 根据用户名查询用户(rpc)
     * @param requestMap
     * @return
     */
    @Override
    public Map<String, Object> getUserInfo(Map<String, Object> requestMap) {
        LoginUser loginUser = LoginInfoContextHelper.getLoginUser();
        String tenantId = loginUser.getTenantId();
        String reqTenantId = (String) requestMap.get("tenantId");
        if(StringUtils.isNotBlank(reqTenantId)){
            tenantId = (String) requestMap.get("tenantId");
        }
        String username = (String) requestMap.get("username");
        SysUser sysUser = userMapper.selectUserInfo(tenantId,username);
        SysTenant sysTenant = tenantMapper.selectTenantInfoByTenantId(tenantId);
        UserResp userResp=new UserResp();
        userResp.setSysTenant(sysTenant);
        userResp.setSysUser(sysUser);
        return RespBodyHandler.setRespBodyDto(userResp);
    }

    /**
     * 分配岗位
     * @param requestMap
     * @return
     */
    @Override
    public Map<String, Object> assignPost(Map<String, Object> requestMap) {
        String userId = (String) requestMap.get("userId");
        List<String> postIds = (List<String>) requestMap.get("postIds");
        if (EmptyChecker.isEmpty(userId)) {
            throw new BusinessException(String.valueOf(ResponseCode.ID_NOT_ISNULL));
        }
        // 岗位id集合为空时，表示解除所有绑定
        userPostMapper.unbindPost(userId);
        if(postIds.size() < 1){
            return RespBodyHandler.RespBodyDto();
        }
        userPostMapper.assignPosts(userId, postIds);
        return RespBodyHandler.RespBodyDto();
    }

    /**
     * 登录
     * @param requestMap
     * @return
     */
    @Override
    public Map<String, Object> login(Map<String, Object> requestMap) {
        String tenantId = (String)requestMap.get("tenantId");
        String username = (String) requestMap.get("username");
        String password = (String) requestMap.get("password");
        // 判断用户名密码是否为空
        if (EmptyChecker.isEmpty(username) || EmptyChecker.isEmpty(password)) {
            throw new BusinessException(String.valueOf(ResponseCode.USERNAME_PASSWORD_ERROR));
        }
        Set<SysApp> appSet = new HashSet<>();
        // 用户选择租户 登录返回的用户对象信息
        SysUser loginUser = userMapper.login(tenantId, username, password);
        if(loginUser == null){
            throw new BusinessException(ResponseCode.USER_PASSWORD_IS_FALSE);
        }
        // 登陆返回的用户机构对象信息
        SysOrg sysOrg = orgMapper.selectInfoById(loginUser.getOrgId());
        // 登陆返回的用户岗位对象信息
        List<SysPost> sysPosts = postMapper.getPostByUserId(loginUser.getUserId());
        List<SysRole> roles = new ArrayList<>();
        for (SysPost post:sysPosts) {
            roles.addAll(roleMapper.getRoleListByPostId(post.getPostId()));
        }
        // 登陆返回的用户角色对象信息
        if (roles.size() > 0 && roles != null) {
            for (SysRole role : roles) {
                // 登录返回的所属用户角色的应用
                SysApp sysApp = appMapper.getAppInfoByAppId(role.getAppId(),tenantId);
                appSet.add(sysApp);
            }
        }
        SysTenant sysTenant = tenantMapper.selectTenantInfoByTenantId(tenantId);

        UserResp userResp=new UserResp();
        userResp.setSysTenant(sysTenant);
        userResp.setSysUser(loginUser);
        userResp.setSysOrg(sysOrg);
        userResp.setSysPost(sysPosts);
        userResp.setSysRoleList(roles);
        userResp.setSysAppSet(appSet);
        return RespBodyHandler.setRespBodyDto(userResp);
    }


    /**
     * 多条件分页查询用户集合
     * @param requestMap
     * @return
     */
    @Override
    public Map<String, Object> getPageListByTenantId(Map<String, Object> requestMap) {
        LoginUser loginUser = LoginInfoContextHelper.getLoginUser();
        String tenantId = loginUser.getTenantId();
        String username = (String)requestMap.get("username");
        String nickname = (String)requestMap.get("nickname");
        String phone = (String)requestMap.get("phone");
        String orgId = (String)requestMap.get("orgId");
        Pagination pagination = (Pagination) requestMap.get("pagination");
        BsinPageUtil.pageNotNull(pagination);
        PageHelper.startPage(pagination.getPageNum(),pagination.getPageSize());
        List<SysUser> userList = userMapper.selectList(tenantId,nickname,username,phone,orgId);
        PageInfo<SysUser> pageInfo = new PageInfo<SysUser>(userList);
        return RespBodyHandler.setRespPageInfoBodyDto(pageInfo);
    }

    /**
     * 根据用户id查询用户能看到的应用
     * 1、用户所在部门能访问的应用，部门下的用户则能查看
     * 2、但是用户进入应用具有的菜单权限根据用户分配的岗位及岗位对应的角色决定
     * userId 为空时是商户登录未认证
     * @param requestMap
     * @return
     */
    @Override
    public Map<String, Object> getAppByUserId(Map<String, Object> requestMap) {
        LoginUser loginUser = LoginInfoContextHelper.getLoginUser();
        String tenantId = LoginInfoContextHelper.getTenantId();
        String userId = loginUser.getUserId();
        List<SysApp> sysApps = new ArrayList<>();
        if(StringUtils.isBlank(userId)){
            SysTenant sysTenant = tenantMapper.selectTenantInfoByTenantId(tenantId);
            SysProduct sysProduct = productMapper.selectByProductCode(sysTenant.getProductCode());
            SysApp baseApp = tenantAppMapper.selectTenantBaseApp(tenantId,sysProduct.getProductId());
            sysApps.add(baseApp);
            return RespBodyHandler.setRespPageInfoBodyDto(new PageInfo<SysApp>(sysApps));
        }
        Pagination pagination = (Pagination) requestMap.get("pagination");
        BsinPageUtil.pageNotNull(pagination);
        SysUser sysUser = userMapper.selectById(userId);
        PageHelper.startPage(pagination.getPageNum(),pagination.getPageSize());
        sysApps = appMapper.selectListByOrgId(sysUser.getOrgId());
        PageInfo<SysApp> pageInfo = new PageInfo<SysApp>(sysApps);
        return RespBodyHandler.setRespPageInfoBodyDto(pageInfo);
    }

    @Override
    public Map<String, Object> getAppListByUserId(Map<String, Object> requestMap) {
        LoginUser loginUser = LoginInfoContextHelper.getLoginUser();
        String tenantId = LoginInfoContextHelper.getTenantId();
        String userId = loginUser.getUserId();
        List<SysApp> sysApps = null;
        SysTenant sysTenant = tenantMapper.selectTenantInfoByTenantId(tenantId);
        SysProduct sysProduct = productMapper.selectByProductCode(sysTenant.getProductCode());
        SysApp baseApp = tenantAppMapper.selectTenantBaseApp(tenantId, sysProduct.getProductId());
        if(StringUtils.isBlank(userId)){
            sysApps = new ArrayList<>();
            sysApps.add(baseApp);
        }else {
            SysUser sysUser = userMapper.selectById(userId);
            sysApps = appMapper.selectListByOrgId(sysUser.getOrgId());
        }
        Map appListResp = new HashMap();
        appListResp.put("apps",sysApps);
        appListResp.put("defaultApp",baseApp);
        return RespBodyHandler.setRespBodyDto(appListResp);
    }


}
